package br.edu.ufcg.splab.techniques.reduction.heuristics;

import java.util.ArrayList;
import java.util.List;

import br.edu.ufcg.splab.generator.TestCase;
import br.edu.ufcg.splab.generator.TestSuite;
import br.edu.ufcg.splab.techniques.reduction.requirement.InterfaceRequirement;
import br.edu.ufcg.splab.techniques.reduction.requirement.RequirementTracer;

public class GreedyEssential extends Greedy {
	
	/**
	 * This heuristic was defined by Chen and Lau and is based on the following
	 * concepts:
	 * <p>Essential concept - selects all essential test cases. 
	 * A test case is essential when only this test case covers one specific requirement;</p>
	 * <p>Greedy heuristic (presented in subsection \ref{G_Heuristic}).</p>
	 * 
	 * Initially, all essential test cases are observed, and their
	 * respective requirements are marked. Then, the greedy heuristic is applied.
	 * 
	 * @param suite The complete test suite.
	 * @param tracers The ordered list of requirements of the complete test suite.
	 * @return The reduced test suite.
	 */
	public TestSuite reduceTestSuite(TestSuite suite, List<RequirementTracer> tracers) {		
		List<TestCase> verifiedTests = new ArrayList<TestCase>(); 
		List<TestCase> reducedTests = new ArrayList<TestCase>();
		List<TestCase> toVerify = new ArrayList<TestCase>(suite.getTestSuite());
		
		for(RequirementTracer tracer: tracers){		
			reducedTests.addAll(verifiedTests);
			
			toVerify = new ArrayList<TestCase>(suite.getTestSuite());
			toVerify.removeAll(reducedTests);
			
			verifiedTests = new ArrayList<TestCase>();		
			
			List<InterfaceRequirement> requirements = tracer.getRequirements();
			for(TestCase tc: reducedTests){
				requirements.removeAll(tracer.getRequirementsSatisfied(tc));
			}
			List<InterfaceRequirement> notCovered = new ArrayList<InterfaceRequirement>(requirements);				
					
			List<TestCase> essentials = tracer.getEssentialTestCases();

			for (TestCase testCase : essentials) {
				requirements = tracer.getRequirementsSatisfied(testCase);
				notCovered.removeAll(requirements);
				toVerify.remove(testCase);
				verifiedTests.add(testCase);
			}
		
			while(notCovered.size() > 0) {
				TestCase mostCoverer = this.getTheMostCovererOfNotSatisfied(toVerify, notCovered, tracer);
				requirements = tracer.getRequirementsSatisfied(mostCoverer);
				notCovered.removeAll(requirements);
				toVerify.remove(mostCoverer);
				verifiedTests.add(mostCoverer);
			}
			
		}		
		
		reducedTests.addAll(verifiedTests);		
	
		TestSuite newTS = new TestSuite();
		newTS.addAll(reducedTests);

		return newTS;
	}

	/**
     * Provide a string representation of the technique to be written.
     */
	public String toString() {
		return "GE";
	}
}
